#ifndef __INCframeworkmgrh
#define __INCframeworkmgrh

#include <map>
#include <mutex>
#include <type.h>
#include <table.h>
#include <objbase.h>
#include <modules.h>
#include <clibase.h>
#include <genericCaller.h>
#include <declarecClass.h>
#include <lvos.h>

class FrameWorkMgr
{
private:
    DECLARE_SINGLETON(FrameWorkMgr);
    class FrameWork
        {
        public:
            std::string objectName;
            objbase *   objectPtr;
            int         objectId;
            int         refCount;

        public:
            FrameWork(const char * name, objbase *objPtr, int objId)
            {
                objectName = name;
                objectPtr  = objPtr;
                objectId = objId;
                refCount = 1;
            }
            ~FrameWork()
            {
                if (objectPtr)
                {
                    delete objectPtr;
                    objectPtr = nullptr;
                }
            }
        };

    template <typename T>
    class AutoRefObject {
    public:
        AutoRefObject(FrameWorkMgr& mgr, int objectId)
            : mgr_(mgr), objectId_(objectId) 
        {
            obj_ = reinterpret_cast<T*>(mgr_.queryRefObject(objectId));
        }

        ~AutoRefObject() 
        {
            if (obj_) mgr_.releaseRefObject(objectId_);
        }

        T* operator()() const { return obj_; }

    private:
        DISABLE_COPY_CLASS(AutoRefObject);
        FrameWorkMgr& mgr_;
        T* obj_;
        int objectId_;
    };

public:
    static std::string getVersion();
    static std::string getBuildTime();
    static void welcome(int fd = STDOUT_FILENO);
    static void welcome(SessionPtr session);
    STATUS waitExit();
    STATUS setExit();
    STATUS objRegister(const char*, objbase *, int);
    STATUS objUnRegister(int objectId);

    template <typename T, typename... Args>
    void callObjectMethod(int objectId, void (T::* func)(Args...), Args&&... args)
    {
        (void)callObjectMethodImpl<T>(objectId, func, std::forward<Args>(args)...);
    }

    template <typename T, typename RetType, typename... Args>
    RetType callObjectMethod(int objectId, RetType(T::* func)(Args...), Args&&... args)
    {
        return callObjectMethodImpl<T>(objectId, func, std::forward<Args>(args)...);
    }

    template <typename T, typename Func, typename... Args>
    void callObjectMethod(int objectId, Func&& func, Args&&... args)
    {
        static_assert(!std::is_member_function_pointer_v<std::decay_t<Func>>,
            "Use member function pointer overload for member functions");
        callObjectMethodImpl<T>(objectId, std::forward<Func>(func), std::forward<Args>(args)...);
    }

    template <typename T, typename RetType, typename Func, typename... Args>
    RetType callObjectMethod(int objectId, Func&& func, Args&&... args)
    {
        static_assert(!std::is_member_function_pointer_v<std::decay_t<Func>>,
            "Use member function pointer overload for member functions");
        return callObjectMethodImpl<T>(objectId, std::forward<Func>(func), std::forward<Args>(args)...);
    }

    friend STATUS clibase::objectDump(const char* name, TextTable &t);
    template <typename T>
    friend class AutoRefObject;

private:
    STATUS init();
    STATUS destory();
    STATUS releaseRefObject(int objectId);
    objbase* queryRefObject(int objectId);
    objbase* queryObjectInternal(int objectId, bool isRef = false);
    template <typename T, typename Callable, typename... Args>
    auto callObjectMethodImpl(int objectId, Callable&& callable, Args&&... args)
    {
        AutoRefObject<T> autoRef(*this, objectId);
        GenericCaller<T> caller(autoRef());
        return caller.call(std::forward<Callable>(callable), std::forward<Args>(args)...);
    }

private:
    std::mutex m_objectLock;
    std::atomic<bool> m_stoped;
    std::map<int, std::shared_ptr<FrameWork>> m_objectList;
};

class FrameWorkMgrCollector
{
public:
    FrameWorkMgrCollector(const char*, objbase *, int);

private:
    DISABLE_COPY_CLASS(FrameWorkMgrCollector);
};

#define GET_FRAMEWORK_MGR  FrameWorkMgr::getInstance()

#define REG_TO_FRAMEWORK(Class, SelfId) \
    static FrameWorkMgrCollector        \
        g_FrameWorkMgrCollector_##Class(#Class, new Class(), SelfId);

#endif
